Add reader for "OpenStreetMap" data files (format osm).
authoroliskoli <oliskoli>
Tue, 1 Apr 2008 18:50:49 +0000 (18:50 +0000)
committeroliskoli <oliskoli>
Tue, 1 Apr 2008 18:50:49 +0000 (18:50 +0000)
Makefile.in
osm.c [new file with mode: 0644]
testo
vecs.c

index 452deef863291f7dae2a3d6bea1343e95ba693a4..659b53c72cc8a637cb94a9a225fcdf05c632cdb7 100644 (file)
@@ -58,7 +58,7 @@ ALL_FMTS=$(MINIMAL_FMTS) gtm.o gpsutil.o pcx.o cetus.o copilot.o \
        yahoo.o unicsv.o wfff_xml.o garmin_txt.o axim_gpb.o gpssim.o \
        wbt-200.o stmsdf.o gtrnctr.o dmtlog.o raymarine.o alan.o vitovtt.o \
        ggv_log.o g7towin.o garmin_gpi.o lmx.o random.o xol.o dg-100.o \
-       navilink.o mtk_logger.o ik3d.o
+       navilink.o mtk_logger.o ik3d.o osm.o
 
 FMTS=@FMTS@
 
@@ -597,6 +597,9 @@ nmn4.o: nmn4.c defs.h config.h queue.h gbtypes.h zlib/zlib.h zlib/zconf.h \
   gbfile.h cet.h cet_util.h inifile.h csv_util.h
 nukedata.o: nukedata.c defs.h config.h queue.h gbtypes.h zlib/zlib.h \
   zlib/zconf.h gbfile.h cet.h cet_util.h inifile.h filterdefs.h
+osm.o: osm.c defs.h config.h queue.h gbtypes.h zlib/zlib.h \
+  zlib/zconf.h gbfile.h cet.h cet_util.h inifile.h xmlgeneric.h \
+  avltree.h
 overlay.o: overlay.c defs.h config.h queue.h gbtypes.h zlib/zlib.h \
   zlib/zconf.h gbfile.h cet.h cet_util.h inifile.h grtcirc.h
 ozi.o: ozi.c defs.h config.h queue.h gbtypes.h zlib/zlib.h zlib/zconf.h \
diff --git a/osm.c b/osm.c
new file mode 100644 (file)
index 0000000..cc717b5
--- /dev/null
+++ b/osm.c
@@ -0,0 +1,691 @@
+/* 
+
+       Reader for "OpenStreetMap" data files (.xml)
+
+       Copyright (C) 2008 Olaf Klein, o.b.klein@gpsbabel.org
+
+       This program is free software; you can redistribute it and/or modify
+       it under the terms of the GNU General Public License as published by
+       the Free Software Foundation; either version 2 of the License, or
+       (at your option) any later version.
+
+       This program is distributed in the hope that it will be useful,
+       but WITHOUT ANY WARRANTY; without even the implied warranty of
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+       GNU General Public License for more details.
+
+       You should have received a copy of the GNU General Public License
+       along with this program; if not, write to the Free Software
+       Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA
+
+*/
+
+#include "defs.h"
+#include "avltree.h"
+#include "xmlgeneric.h"
+
+static arglist_t osm_args[] = 
+{
+       ARG_TERMINATOR
+};
+
+#define MYNAME "osm"
+
+#if ! HAVE_LIBEXPAT
+void
+osm_rd_init(const char *fname)
+{
+       fatal(MYNAME ": This build excluded \" MYNAME \" support because expat was not installed.\n");
+}
+
+void
+osm_read(void)
+{
+}
+
+#else
+
+static waypoint *wpt;
+static route_head *rte;
+static int wpt_loaded, rte_loaded;
+
+static avltree_t *waypoints;   /* AVL tree */
+static avltree_t *keys = NULL;
+static avltree_t *values = NULL;
+
+static xg_callback     osm_node, osm_node_tag, osm_node_end;
+static xg_callback     osm_way, osm_way_nd, osm_way_tag, osm_way_end;
+
+static 
+xg_tag_mapping osm_map[] = {
+       { osm_node,     cb_start,       "/osm/node" },
+       { osm_node_tag, cb_start,       "/osm/node/tag" },
+       { osm_node_end, cb_end,         "/osm/node" },
+       { osm_way,      cb_start,       "/osm/way" },
+       { osm_way_nd,   cb_start,       "/osm/way/nd" },
+       { osm_way_tag,  cb_start,       "/osm/way/tag" },
+       { osm_way_end,  cb_end,         "/osm/way" },
+       { NULL,         0,              NULL }
+};
+
+static char *osm_features[] = {
+       "- dummy -",    /*  0 */
+       "aeroway",      /*  1 */
+       "amenity",      /*  2 */
+       "building",     /*  3 */
+       "cycleway",     /*  4 */
+       "railway",      /*  5 */
+       "highway",      /*  6 */
+       "historic",     /*  7 */
+       "landuse",      /*  8 */
+       "leisure",      /*  9 */
+       "man_made",     /* 10 */
+       "military",     /* 11 */
+       "natural",      /* 12 */
+       "place",        /* 13 */
+       "power",        /* 14 */
+       "shop",         /* 15 */
+       "sport",        /* 16 */
+       "tourism",      /* 17 */
+       "waterway",     /* 18 */
+       "aerialway",    /* 19 */
+       NULL
+};
+
+typedef struct osm_icon_mapping_s {
+       const char key;
+       const char *value;
+       const char *icon;
+} osm_icon_mapping_t;
+
+
+/* based on <http://wiki.openstreetmap.org/index.php/Map_Features> */
+
+static osm_icon_mapping_t osm_icon_mappings[] = {
+
+       /* cycleway ...*/
+
+       /* highway ...*/
+
+//     { 6, "mini_roundabout",         "?" },
+//     { 6, "stop",                    "?" },
+//     { 6, "traffic_signals",         "?" },
+//     { 6, "crossing",                "?" },
+//     { 6, "gate",                    "?" },
+//     { 6, "stile",                   "?" },
+//     { 6, "cattle_grid",             "?" },
+//     { 6, "toll_booth",              "?" },
+//     { 6, "incline",                 "?" },
+//     { 6, "incline_steep",           "?" },
+//     { 6, "viaduct",                 "?" },
+//     { 6, "motorway_junction",       "?" },
+//     { 6, "services",                "?" },
+//     { 6, "ford",                    "?" },
+//     { 6, "bus_stop",                "?" },
+//     { 6, "turning_circle",          "?" },
+//     { 6, "User Defined",            "?" },
+
+       /* waterway ... */
+
+       { 18, "dock",                   "Dock" },
+//     { 18, "lock_gate",              "?" },
+//     { 18, "turning_point",          "?" },
+//     { 18, "aqueduct",               "?" },
+//     { 18, "boatyard",               "?" },
+//     { 18, "water_point",            "?" },
+//     { 18, "waste_disposal",         "?" },
+//     { 18, "mooring",                "?" },
+//     { 18, "weir",                   "?" },
+//     { 18, "User Defined",           "?" },
+
+       /* railway ... */
+
+//     { 5, "station",                 "?" },
+//     { 5, "halt",                    "?" },
+//     { 5, "tram_stop",               "?" },
+//     { 5, "viaduct",                 "?" },
+       { 5, "crossing",                "Crossing" },
+//     { 5, "level_crossing",          "?" },
+//     { 5, "subway_entrance",         "?" },
+//     { 5, "turntable",               "?" },
+//     { 5, "User Defined",            "?" },
+
+       /* aeroway ... */
+
+       { 1, "aerodrome",               "Airport" },
+       { 1, "terminal",                "Airport" },
+       { 1, "helipad",                 "Heliport" },
+//     { 1, "User Defined",            "?" },
+
+       /* aerialway ... */
+
+//     { 19, "User Defined",           "?" },
+
+       /* power ... */
+
+//     { 14, "tower",                  "?" },
+//     { 14, "sub_station",            "?" },
+//     { 14, "generator",              "?" },
+
+       /* man_made ... */
+
+//     { 10, "works",                  "?" },
+//     { 10, "beacon",                 "?" },
+//     { 10, "survey_point",           "?" },
+//     { 10, "power_wind",             "?" },
+//     { 10, "power_hydro",            "?" },
+//     { 10, "power_fossil",           "?" },
+//     { 10, "power_nuclear",          "?" },
+//     { 10, "tower",                  "?" },
+//     { 10, "water_tower",            "?" },
+//     { 10, "gasometer",              "?" },
+//     { 10, "reservoir_covered",      "?" },
+//     { 10, "lighthouse",             "?" },
+//     { 10, "windmill",               "?" },
+//     { 10, "wastewater_plant",       "?" },
+//     { 10, "crane",                  "?" },
+//     { 10, "User Defined",           "?" },
+
+       /* building ... */
+
+       { 3, "yes",                     "Building" },
+//     { 3, "User Defined",            "?" },
+
+       /* leisure ... */
+
+//     { 9, "sports_centre",           "?" },
+       { 9, "golf_course",             "Golf Course" },
+       { 9, "stadium",                 "Stadium" },
+//     { 9, "track",                   "?" },
+//     { 9, "pitch",                   "?" },
+//     { 9, "water_park",              "?" },
+       { 9, "marina",                  "Marina" },
+//     { 9, "slipway",                 "?" },
+       { 9, "fishing",                 "Fishing Area" },
+//     { 9, "nature_reserve",          "?" },
+       { 9, "park",                    "Park" },
+//     { 9, "playground",              "?" },
+//     { 9, "garden",                  "?" },
+//     { 9, "common",                  "?" },
+//     { 9, "User Defined",            "?" },
+
+       /* amenity ... */
+
+       { 2, "pub",                     "Bar" },
+//     { 2, "biergarten",              "?" },
+       { 2, "nightclub",               "Bar" },
+//     { 2, "cafe",                    "?" },
+       { 2, "restaurant",              "Restaurant" },
+       { 2, "fast_food",               "Fast Food" },
+       { 2, "parking",                 "Parking Area" },
+//     { 2, "bicycle_parking",         "?" },
+//     { 2, "bicycle_rental",          "?" },
+       { 2, "car_rental",              "Car Rental" },
+//     { 2, "car_sharing",             "?" },
+//     { 2, "taxi",                    "?" },
+       { 2, "fuel",                    "Gas Station" },
+       { 2, "telephone",               "Telephone" },
+       { 2, "toilets",                 "Restroom" },
+//     { 2, "recycling",               "?" },
+//     { 2, "public_building",         "?" },
+       { 2, "townhall",                "City Hall" },
+//     { 2, "place_of_worship",        "?" },
+//     { 2, "grave_yard",              "?" },
+       { 2, "post_office",             "Post Office" },
+//     { 2, "post_box",                "?" },
+       { 2, "school",                  "School" },
+//     { 2, "university",              "?" },
+//     { 2, "college",                 "?" },
+       { 2, "pharmacy",                "Pharmacy" },
+       { 2, "hospital",                "Medical Facility" },
+//     { 2, "library",                 "?" },
+       { 2, "police",                  "Police Station" },
+//     { 2, "fire_station",            "?" },
+//     { 2, "bus_station",             "?" },
+//     { 2, "theatre",                 "?" },
+//     { 2, "cinema",                  "?" },
+//     { 2, "arts_centre",             "?" },
+//     { 2, "courthouse",              "?" },
+//     { 2, "prison",                  "?" },
+       { 2, "bank",                    "Bank" },
+//     { 2, "bureau_de_change",        "?" },
+//     { 2, "atm",                     "?" },
+//     { 2, "fountain",                "?" },
+//     { 2, "User Defined",            "?" },
+
+       /* shop ... */
+
+//     { 15, "supermarket",            "?" },
+       { 15, "convenience",            "Convenience Store" },
+//     { 15, "butcher",                "?" },
+//     { 15, "bicycle",                "?" },
+//     { 15, "doityourself",           "?" },
+//     { 15, "dry_cleaning",           "?" },
+//     { 15, "laundry",                "?" },
+//     { 15, "outdoor",                "?" },
+//     { 15, "kiosk",                  "?" },
+//     { 15, "User Defined",           "?" },
+
+       /* tourism ... */
+
+       { 17, "information",            "Information" },
+       { 17, "hotel",                  "Hotel" },
+       { 17, "motel",                  "Lodging" },
+       { 17, "guest_house",            "Lodging" },
+       { 17, "hostel",                 "Lodging" },
+       { 17, "camp_site",              "Campground" },
+       { 17, "caravan_site",           "RV Park" },
+       { 17, "picnic_site",            "Picnic Area" },
+       { 17, "viewpoint",              "Scenic Area" },
+//     { 17, "theme_park",             "?" },
+//     { 17, "attraction",             "?" },
+       { 17, "zoo",                    "Zoo" },
+//     { 17, "artwork",                "?" },
+       { 17, "museum",                 "Museum" },
+//     { 17, "User Defined",           "?" },
+
+       /* historic ... */
+
+//     { 7, "castle",                  "?" },
+//     { 7, "monument",                "?" },
+//     { 7, "memorial",                "?" },
+//     { 7, "archaeological_site",     "?" },
+//     { 7, "ruins",                   "?" },
+//     { 7, "battlefield",             "?" },
+//     { 7, "User Defined",            "?" },
+
+       /* landuse ... */
+
+//     { 8, "farm",                    "?" },
+//     { 8, "quarry",                  "?" },
+//     { 8, "landfill",                "?" },
+//     { 8, "basin",                   "?" },
+//     { 8, "reservoir",               "?" },
+       { 8, "forest",                  "Forest" },
+//     { 8, "allotments",              "?" },
+//     { 8, "residential",             "?" },
+//     { 8, "retail",                  "?" },
+//     { 8, "commercial",              "?" },
+//     { 8, "industrial",              "?" },
+//     { 8, "brownfield",              "?" },
+//     { 8, "greenfield",              "?" },
+//     { 8, "railway",                 "?" },
+//     { 8, "construction",            "?" },
+       { 8, "military",                "Military" },
+       { 8, "cemetery",                "Cemetery" },
+//     { 8, "village_green",           "?" },
+//     { 8, "recreation_ground",       "?" },
+//     { 8, "User Defined",            "?" },
+
+       /* military ... */
+
+//     { 11, "airfield",               "?" },
+//     { 11, "bunker",                 "?" },
+//     { 11, "barracks",               "?" },
+//     { 11, "danger_area",            "?" },
+//     { 11, "range",                  "?" },
+//     { 11, "naval_base",             "?" },
+//     { 11, "User Defined",           "?" },
+
+       /* natural ... */
+
+//     { 12, "spring",                 "?" },
+//     { 12, "peak",                   "?" },
+//     { 12, "glacier",                "?" },
+//     { 12, "volcano",                "?" },
+//     { 12, "cliff",                  "?" },
+//     { 12, "scree",                  "?" },
+//     { 12, "scrub",                  "?" },
+//     { 12, "fell",                   "?" },
+//     { 12, "heath",                  "?" },
+//     { 12, "wood",                   "?" },
+//     { 12, "marsh",                  "?" },
+//     { 12, "water",                  "?" },
+//     { 12, "coastline",              "?" },
+//     { 12, "mud",                    "?" },
+       { 12, "beach",                  "Beach" },
+//     { 12, "bay",                    "?" },
+//     { 12, "land",                   "?" },
+//     { 12, "cave_entrance",          "?" },
+//     { 12, "User Defined",           "?" },
+
+       /* sport ... */
+
+//     { 16, "10pin",                  "?" },
+//     { 16, "athletics",              "?" },
+//     { 16, "australian_football",    "?" },
+//     { 16, "baseball",               "?" },
+//     { 16, "basketball",             "?" },
+//     { 16, "boules",                 "?" },
+//     { 16, "bowls",                  "?" },
+//     { 16, "climbing",               "?" },
+//     { 16, "cricket",                "?" },
+//     { 16, "cricket_nets",           "?" },
+//     { 16, "croquet",                "?" },
+//     { 16, "cycling",                "?" },
+//     { 16, "dog_racing",             "?" },
+//     { 16, "equestrian",             "?" },
+//     { 16, "football",               "?" },
+//     { 16, "golf",                   "?" },
+//     { 16, "gymnastics",             "?" },
+//     { 16, "hockey",                 "?" },
+//     { 16, "horse_racing",           "?" },
+//     { 16, "motor",                  "?" },
+//     { 16, "multi",                  "?" },
+//     { 16, "pelota",                 "?" },
+//     { 16, "racquet",                "?" },
+//     { 16, "rugby",                  "?" },
+//     { 16, "skating",                "?" },
+//     { 16, "skateboard",             "?" },
+//     { 16, "soccer",                 "?" },
+       { 16, "swimming",               "Swimming Area" },
+       { 16, "skiing",                 "Skiing Area" },
+//     { 16, "table_tennis",           "?" },
+//     { 16, "tennis",                 "?" },
+//     { 16, "orienteering",           "?" },
+//     { 16, "User Defined",           "?" },
+
+       /* place ... */
+
+//     { 13, "continent",              "?" },
+//     { 13, "country",                "?" },
+//     { 13, "state",                  "?" },
+//     { 13, "region",                 "?" },
+//     { 13, "county",                 "?" },
+       { 13, "city",                   "City (Large)" },
+       { 13, "town",                   "City (Medium)" },
+       { 13, "village",                "City (Small)" },
+//     { 13, "hamlet",                 "?" },
+//     { 13, "suburb",                 "?" },
+//     { 13, "locality",               "?" },
+//     { 13, "island",                 "?" },
+//     { 13, "User Defined",           "?" },
+
+       { -1, NULL, NULL }
+};
+
+
+static void
+osm_features_init(void)
+{
+       int i;
+
+       keys = avltree_init(0, MYNAME);
+       values = avltree_init(0, MYNAME);
+       
+       /* the first of osm_features is a place holder */
+       for (i = 1; osm_features[i]; i++)
+               avltree_insert(keys, osm_features[i], (void *)i);
+       
+       for (i = 0; osm_icon_mappings[i].value; i++) {
+               char buff[128];
+
+               buff[0] = osm_icon_mappings[i].key;
+               strncpy(&buff[1], osm_icon_mappings[i].value, sizeof(buff) - 1);
+               avltree_insert(values, buff, (void *)&osm_icon_mappings[i]);
+       }
+}
+
+
+static char
+osm_feature_ikey(const char *key)
+{
+       int result;
+       const void *data;
+       
+       if (avltree_find(keys, key, &data))
+               result = (int)data;
+       else
+               result = -1;
+
+       return result;
+}
+
+
+static char *
+osm_feature_symbol(const char ikey, const char *value)
+{
+       char *result;
+       char buff[128];
+       const void *data;
+
+       buff[0] = ikey;
+       strncpy(&buff[1], value, sizeof(buff) - 1);
+
+       if (avltree_find(values, buff, &data))
+               result = xstrdup(((osm_icon_mapping_t *)data)->icon);
+       else
+               xasprintf(&result, "%s:%s", osm_features[(int)ikey], value);
+
+       return result;
+}
+
+
+static char *
+osm_strip_html(const char *str)
+{
+       utf_string utf;
+       utf.is_html = 1;
+       utf.utfstring = (char *)str;
+
+       return strip_html(&utf);        // util.c
+}
+
+
+static void 
+osm_node_end(const char *args, const char **unused)
+{
+       if (wpt) {
+               if (wpt->wpt_flags.fmt_use)
+                       waypt_add(wpt);
+               else
+                       waypt_free(wpt);
+               wpt = NULL;
+       }
+}
+
+
+static void 
+osm_node(const char *args, const char **attrv)
+{
+       const char **avp = &attrv[0];
+
+       wpt = waypt_new();
+
+        while (*avp) {
+               if (strcmp(avp[0], "id") == 0) {
+                       xasprintf(&wpt->description, "osm-id %s", avp[1]);
+                       if (! avltree_insert(waypoints, avp[1], (void *)wpt))
+                               warning(MYNAME ": Duplicate osm-id %s!\n", avp[1]);
+                       else
+                               wpt->wpt_flags.fmt_use = 1;
+               }
+               else if (strcmp(avp[0], "user") == 0) ;
+               else if (strcmp(avp[0], "lat") == 0)
+                       wpt->latitude = atof(avp[1]);
+               else if (strcmp(avp[0], "lon") == 0)
+                       wpt->longitude = atof(avp[1]);
+               else if (strcmp(avp[0], "timestamp") == 0)
+                       wpt->creation_time = xml_parse_time(avp[1], &wpt->microseconds);
+
+               avp += 2;
+       }
+}
+
+
+static void 
+osm_node_tag(const char *args, const char **attrv)
+{
+       const char **avp = &attrv[0];
+       const char *key = "", *value = "";
+       char *str;
+       char ikey;
+       
+        while (*avp) {
+               if (strcmp(avp[0], "k") == 0)
+                       key = avp[1];
+               else if (strcmp(avp[0], "v") == 0)
+                       value = avp[1];
+               avp+=2;
+       }
+       
+       str = osm_strip_html(value);
+       
+       if (strcmp(key, "name") == 0) {
+               if (! wpt->shortname)
+                       wpt->shortname = xstrdup(str);
+       }
+       else if (strcmp(key, "name:en") == 0) {
+               if (wpt->shortname)
+                       xfree(wpt->shortname);
+               wpt->shortname = xstrdup(str);
+       }
+       else if ((ikey = osm_feature_ikey(key)) >= 0) {
+               wpt->icon_descr = osm_feature_symbol(ikey, value);
+               wpt->wpt_flags.icon_descr_is_dynamic = 1;
+       }
+       else if (strcmp(key, "note") == 0) {
+               if (wpt->notes) {
+                       char *tmp;
+                       xasprintf(&tmp, "%s; %s", wpt->notes, str);
+                       xfree(wpt->notes);
+                       wpt->notes = tmp;
+               }
+               else
+                       wpt->notes = xstrdup(str);
+       }
+       
+       xfree(str);
+}
+
+
+static void 
+osm_way(const char *args, const char **attrv)
+{
+       const char **avp = &attrv[0];
+
+       rte = route_head_alloc();
+
+        while (*avp) {
+               if (strcmp(avp[0], "id") == 0) {
+                       xasprintf(&rte->rte_desc, "osm-id %s", avp[1]);
+               }
+               avp += 2;
+       }
+}
+
+static void 
+osm_way_nd(const char *args, const char **attrv)
+{
+       const char **avp = &attrv[0];
+
+        while (*avp) {
+               if (strcmp(avp[0], "ref") == 0) {
+                       waypoint *tmp;
+                       if (avltree_find(waypoints, avp[1], (void *)&tmp)) {
+                               tmp = waypt_dupe(tmp);
+                               route_add_wpt(rte, tmp);
+                       }
+                       else
+                               warning(MYNAME ": Way reference id \"%s\" wasn't listed under nodes!\n", avp[1]);
+               }
+               avp += 2;
+       }
+}
+
+static void 
+osm_way_tag(const char *args, const char **attrv)
+{
+       const char **avp = &attrv[0];
+       const char *key = "", *value = "";
+       char *str;
+       
+        while (*avp) {
+               if (strcmp(avp[0], "k") == 0)
+                       key = avp[1];
+               else if (strcmp(avp[0], "v") == 0)
+                       value = avp[1];
+               avp += 2;
+       }
+       
+       str = osm_strip_html(value);
+       
+       if (strcmp(key, "name") == 0) {
+               if (! rte->rte_name)
+                       rte->rte_name = xstrdup(str);
+       }
+       else if (strcmp(key, "name:en") == 0) {
+               if (rte->rte_name)
+                       xfree(rte->rte_name);
+               rte->rte_name = xstrdup(str);
+       }
+       
+       xfree(str);
+}
+
+static void 
+osm_way_end(const char *args, const char **unused)
+{
+       if (rte) {
+               route_add_head(rte);
+               rte = NULL;
+       }
+}
+
+static void 
+osm_rd_init(const char *fname)
+{
+       wpt = NULL;
+       rte = NULL;
+       wpt_loaded = 0;
+       rte_loaded = 0;
+
+       waypoints = avltree_init(0, MYNAME);
+       if (! keys)
+               osm_features_init();
+
+       xml_init(fname, osm_map, NULL);
+}
+
+static void 
+osm_read(void)
+{
+       xml_read();
+       avltree_done(waypoints);
+}
+
+#endif
+
+static void 
+osm_rd_deinit(void)
+{
+       xml_deinit();
+}
+
+static void
+osm_exit(void)
+{
+       if (keys)
+               avltree_done(keys);
+       if (values)
+               avltree_done(values);
+}
+
+
+ff_vecs_t osm_vecs = {
+       ff_type_file,
+       {
+         ff_cap_read,  /* waypoints */
+         ff_cap_none,  /* tracks */
+         ff_cap_read   /* routes */
+       },
+       osm_rd_init,    
+       NULL,   
+       osm_rd_deinit,
+       NULL,
+       osm_read,
+       NULL,
+       osm_exit,
+       osm_args,
+       CET_CHARSET_UTF8, 0
+};
diff --git a/testo b/testo
index 75999178d5a1743795377cff3e5937252bb192f8..dcb4d30ae44fd0e6125b83685a0145a3e20587b3 100755 (executable)
--- a/testo
+++ b/testo
@@ -1303,5 +1303,10 @@ compare ${TMPDIR}/mtk_logger.csv ${REFERENCE}/track/mtk_logger.csv
 ${PNAME} -i ik3d -f ${REFERENCE}/ik3d-sample.ikt -o gpx -F ${TMPDIR}/ik3d-sample.gpx
 compare ${TMPDIR}/ik3d-sample.gpx ${REFERENCE}/ik3d-sample.gpx
 
+# osm data files
+rm -f ${TMPDIR}/osm-*
+${PNAME} -i osm -f ${REFERENCE}/osm-data.xml -o gpx -F ${TMPDIR}/osm-data.gpx
+compare ${TMPDIR}/osm-data.gpx ${REFERENCE}/osm-data.gpx
+
 
 exit 0
diff --git a/vecs.c b/vecs.c
index 3b90a1d25d3cba1ab0e16cb23f1ebeea5ba540d4..e3169f184c0ddf0f7b6de55d777dcd9871f30ac9 100644 (file)
--- a/vecs.c
+++ b/vecs.c
@@ -131,6 +131,7 @@ extern ff_vecs_t random_vecs;
 extern ff_vecs_t xol_vecs;
 extern ff_vecs_t navilink_vecs;
 extern ff_vecs_t ik3d_vecs;
+extern ff_vecs_t osm_vecs;
 
 static
 vecs_t vec_list[] = {
@@ -732,6 +733,12 @@ vecs_t vec_list[] = {
                 "MagicMaps IK3D project file (.ikt)",
                 "ikt"
         },
+        {
+                &osm_vecs,
+                "osm",
+                "OpenStreetMap data files",
+                "xml"
+        },
 #endif // MAXIMAL_ENABLED
        {
                NULL,